/*
 * Event.cpp
 *
 *  Created on: 2011/07/02
 *      Author: naoki
 */

#include "NTEngine/NTEngine.h"
#include "NTEngine/Threading/Event.h"
#include "NTEngine/Threading/Function.h"
#include "NTEngine/Base/ReferenceCounter.h"
#include <pthread.h>

namespace NTEngine {
namespace Threading {

class Event::Impl : public ReferenceCounter {
public:
	Impl( bool state )
	: mStatus( state ? SIGNALED : RESET ) {
		pthread_mutex_init( &mMutex, NULL );
		pthread_cond_init( &mCondition, NULL );
	}

	~Impl() {
		pthread_cond_destroy( &mCondition );
		pthread_mutex_destroy( &mMutex );
	}

	void wait() {
		pthread_mutex_lock( &mMutex );
		if ( mStatus == SIGNALED ) {
			// シグナル状態なら何もせず返す
			pthread_mutex_unlock( &mMutex );
			return;
		}
		mStatus = WAITANY;
		while ( mStatus == WAITANY ) {
			pthread_cond_wait( &mCondition, &mMutex );
		}
		pthread_mutex_unlock( &mMutex );
	}

	void isSet( bool* ret ) {
		pthread_mutex_lock( &mMutex );
		*ret = ( mStatus == SIGNALED );
		pthread_mutex_unlock( &mMutex );
	}

	void reset() {
		pthread_mutex_lock( &mMutex );
		mStatus = RESET;
		pthread_mutex_unlock( &mMutex );
	}

	void set() {
		pthread_mutex_lock( &mMutex );
		bool postSignal = ( mStatus == WAITANY );
		mStatus = SIGNALED;
		if ( postSignal ) {
			pthread_cond_broadcast( &mCondition );
		}
		pthread_mutex_unlock( &mMutex );
	}

	pthread_mutex_t mMutex;
	pthread_cond_t mCondition;
	enum {
		RESET,
		WAITANY,
		SIGNALED
	} mStatus;
};

Event Event::create( bool state ) {
	Event ret;
	ret.mImpl = NEW Impl( state );
	return ret;
}

void Event::wait() const {
	mImpl->wait();
}

bool Event::isSet() const {
	bool ret;
	mImpl->isSet( &ret );
	return ret;
}

void Event::set() {
	mImpl->set();
}

void Event::reset() {
	mImpl->reset();
}

#define TYPE Event
#include "NTEngine/Base/Impl/ReferenceCounterTemplate.h"

} // namespace Threading
} // namespace NTEngine
